home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpuzzles.3 / xpuzzles / xpuzzles-5.3.1 / xhexagons / Hexagons.c < prev    next >
C/C++ Source or Header  |  1996-02-14  |  50KB  |  1,643 lines

  1. /*
  2. # X-BASED HEXAGONS
  3. #
  4. #  Hexagons.c
  5. #
  6. ###
  7. #
  8. #  Copyright (c) 1994 - 96    David Albert Bagley, bagleyd@hertz.njit.edu
  9. #
  10. #                   All Rights Reserved
  11. #
  12. #  Permission to use, copy, modify, and distribute this software and
  13. #  its documentation for any purpose and without fee is hereby granted,
  14. #  provided that the above copyright notice appear in all copies and
  15. #  that both that copyright notice and this permission notice appear in
  16. #  supporting documentation, and that the name of the author not be
  17. #  used in advertising or publicity pertaining to distribution of the
  18. #  software without specific, written prior permission.
  19. #
  20. #  This program is distributed in the hope that it will be "playable",
  21. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  23. #
  24. */
  25.  
  26. /* Methods file for Hexagons */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #ifdef VMS
  31. #include <unixlib.h>
  32. #else
  33. #ifndef apollo
  34. #include <unistd.h>
  35. #endif
  36. #endif
  37. #include <X11/IntrinsicP.h>
  38. #include <X11/Intrinsic.h>
  39. #include <X11/StringDefs.h>
  40. #include <X11/CoreP.h>
  41. #include "HexagonsP.h"
  42.  
  43. #ifndef DATAFILE
  44. #define DATAFILE "/usr/games/lib/hexagons.data"
  45. #endif
  46.  
  47. static void InitializeHexagons();
  48. static void ExposeHexagons();
  49. static void ResizeHexagons();
  50. static void DestroyHexagons();
  51. static Boolean SetValuesHexagons();
  52. static void QuitHexagons();
  53. static void MoveHexagonsTl();
  54. static void MoveHexagonsTr();
  55. static void MoveHexagonsLeft();
  56. static void MoveHexagonsRight();
  57. static void MoveHexagonsBl();
  58. static void MoveHexagonsBr();
  59. static void SelectHexagons();
  60. static void ReleaseHexagons();
  61. static void RandomizeHexagons();
  62. static void RandomizeHexagonsMaybe();
  63. static void GetHexagons();
  64. static void WriteHexagons();
  65. static void UndoHexagons();
  66. static void SolveHexagons();
  67. static void IncrementHexagons();
  68. static void DecrementHexagons();
  69. static void CornerHexagons();
  70. static int MoveHexagons();
  71. static int PositionToTile();
  72. static void SelectCornerTiles();
  73. static void SelectNoCornTiles();
  74. static void CheckTiles();
  75. static void ResetTiles();
  76. static void ResizeTiles();
  77. static int MovableCornerTiles();
  78. static void MoveNoTiles();
  79. static int MoveTilesDir();
  80. static int MoveCornerTilesDir();
  81. static int MoveNoCornTilesDir();
  82. static void RandomizeTiles();
  83. static void MoveCornerTiles();
  84. static void MoveNoCornTiles();
  85. static int ExchangeTiles();
  86. #ifdef DEBUG
  87. static int WithinFrame();
  88. #endif
  89. static int NextToWall();
  90. static int TileNextToSpace();
  91. static int FindTileTriangle();
  92. static int FindDir();
  93. static int FindSpaceType();
  94. static void FindMovableTile();
  95. static void DrawFrame();
  96. static void DrawTile();
  97. #ifdef DEBUG
  98. static int PositionInRow();
  99. #endif
  100. static int PositionFromRow();
  101. static int Sqrt();
  102. static void swap();
  103.  
  104. static char defaultTranslationsHexagons[] =
  105.   "<KeyPress>q: Quit()\n\
  106.    Ctrl<KeyPress>C: Quit()\n\
  107.    <KeyPress>Home: MoveTl()\n\
  108.    <KeyPress>KP_7: MoveTl()\n\
  109.    <KeyPress>R7: MoveTl()\n\
  110.    <KeyPress>Prior: MoveTr()\n\
  111.    <KeyPress>KP_9: MoveTr()\n\
  112.    <KeyPress>R9: MoveTr()\n\
  113.    <KeyPress>Left: MoveLeft()\n\
  114.    <KeyPress>KP_4: MoveLeft()\n\
  115.    <KeyPress>R10: MoveLeft()\n\
  116.    <KeyPress>Right: MoveRight()\n\
  117.    <KeyPress>KP_6: MoveRight()\n\
  118.    <KeyPress>R12: MoveRight()\n\
  119.    <KeyPress>End: MoveBl()\n\
  120.    <KeyPress>KP_1: MoveBl()\n\
  121.    <KeyPress>R13: MoveBl()\n\
  122.    <KeyPress>Next: MoveBr()\n\
  123.    <KeyPress>KP_3: MoveBr()\n\
  124.    <KeyPress>R15: MoveBr()\n\
  125.    <Btn1Down>: Select()\n\
  126.    <Btn1Up>: Release()\n\
  127.    <KeyPress>r: Randomize()\n\
  128.    <Btn3Down>(2+): Randomize()\n\
  129.    <Btn3Down>: RandomizeMaybe()\n\
  130.    <KeyPress>g: Get()\n\
  131.    <KeyPress>w: Write()\n\
  132.    <KeyPress>u: Undo()\n\
  133.    <KeyPress>s: Solve()\n\
  134.    <KeyPress>i: Increment()\n\
  135.    <KeyPress>d: Decrement()\n\
  136.    <KeyPress>c: Corner()";
  137.  
  138. static XtActionsRec actionsListHexagons[] =
  139. {
  140.   {"Quit", (XtActionProc) QuitHexagons},
  141.   {"MoveTl", (XtActionProc) MoveHexagonsTl},
  142.   {"MoveTr", (XtActionProc) MoveHexagonsTr},
  143.   {"MoveLeft", (XtActionProc) MoveHexagonsLeft},
  144.   {"MoveRight", (XtActionProc) MoveHexagonsRight},
  145.   {"MoveBl", (XtActionProc) MoveHexagonsBl},
  146.   {"MoveBr", (XtActionProc) MoveHexagonsBr},
  147.   {"Select", (XtActionProc) SelectHexagons},
  148.   {"Release", (XtActionProc) ReleaseHexagons},
  149.   {"Randomize", (XtActionProc) RandomizeHexagons},
  150.   {"RandomizeMaybe", (XtActionProc) RandomizeHexagonsMaybe},
  151.   {"Get", (XtActionProc) GetHexagons},
  152.   {"Write", (XtActionProc) WriteHexagons},
  153.   {"Undo", (XtActionProc) UndoHexagons},
  154.   {"Solve", (XtActionProc) SolveHexagons},
  155.   {"Increment", (XtActionProc) IncrementHexagons},
  156.   {"Decrement", (XtActionProc) DecrementHexagons},
  157.   {"Corner", (XtActionProc) CornerHexagons}
  158. };
  159.  
  160. static XtResource resourcesHexagons[] =
  161. {
  162.   {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  163.    XtOffset(HexagonsWidget, hexagons.foreground), XtRString,
  164.    XtDefaultForeground},
  165.   {XtNtileColor, XtCColor, XtRPixel, sizeof(Pixel),
  166.    XtOffset(HexagonsWidget, hexagons.tileColor), XtRString,
  167.    XtDefaultForeground},
  168.   {XtNtileBorder, XtCColor, XtRPixel, sizeof(Pixel),
  169.    XtOffset(HexagonsWidget, hexagons.borderColor), XtRString,
  170.    XtDefaultForeground},
  171.   {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  172.    XtOffset(HexagonsWidget, core.width), XtRString, "259"},
  173.   {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  174.    XtOffset(HexagonsWidget, core.height), XtRString, "200"},
  175.   {XtNsize, XtCSize, XtRInt, sizeof(int),
  176.    XtOffset(HexagonsWidget, hexagons.size), XtRString, "3"}, /* DEFAULTHEXS */
  177.   {XtNcorners, XtCCorners, XtRBoolean, sizeof(Boolean),
  178.    XtOffset(HexagonsWidget, hexagons.corners), XtRString, "TRUE"},/*DEFAULTCORN*/
  179.   {XtNbase, XtCBase, XtRInt, sizeof(int),
  180.    XtOffset(HexagonsWidget, hexagons.base), XtRString, "10"},
  181.   {XtNstart, XtCBoolean, XtRBoolean, sizeof(Boolean),
  182.    XtOffset(HexagonsWidget, hexagons.started), XtRString, "FALSE"},
  183.   {XtNselectCallback, XtCCallback, XtRCallback, sizeof(caddr_t),
  184.    XtOffset(HexagonsWidget, hexagons.select), XtRCallback, NULL}
  185. };
  186.  
  187. HexagonsClassRec hexagonsClassRec =
  188. {
  189.   {
  190.     (WidgetClass) &widgetClassRec,    /* superclass */
  191.     "Hexagons",                /* class name */
  192.     sizeof(HexagonsRec),        /* widget size */
  193.     NULL,                /* class initialize */
  194.     NULL,                /* class part initialize */
  195.     FALSE,                /* class inited */
  196.     InitializeHexagons,            /* initialize */
  197.     NULL,                /* initialize hook */
  198.     XtInheritRealize,            /* realize */
  199.     actionsListHexagons,        /* actions */
  200.     XtNumber(actionsListHexagons),    /* num actions */
  201.     resourcesHexagons,            /* resources */
  202.     XtNumber(resourcesHexagons),    /* num resources */
  203.     NULLQUARK,                /* xrm class */
  204.     TRUE,                /* compress motion */
  205.     TRUE,                /* compress exposure */
  206.     TRUE,                /* compress enterleave */
  207.     TRUE,                /* visible interest */
  208.     DestroyHexagons,            /* destroy */
  209.     ResizeHexagons,            /* resize */
  210.     ExposeHexagons,            /* expose */
  211.     SetValuesHexagons,            /* set values */
  212.     NULL,                /* set values hook */
  213.     XtInheritSetValuesAlmost,        /* set values almost */
  214.     NULL,                /* get values hook */
  215.     NULL,                /* accept focus */
  216.     XtVersion,                /* version */
  217.     NULL,                /* callback private */
  218.     defaultTranslationsHexagons,    /* tm table */
  219.     NULL,                /* query geometry */
  220.     NULL,                /* display accelerator */
  221.     NULL                /* extension */
  222.   },
  223.   {
  224.     0                    /* ignore */
  225.   }
  226. };
  227.  
  228. WidgetClass hexagonsWidgetClass = (WidgetClass) &hexagonsClassRec;
  229.  
  230. static XPoint hexagonUnit[MAXORIENT][7] =
  231. {
  232.   { {0, 0}, {2, 0}, {1, 1}, {-1, 1}, {-2,  0}, {-1, -1}, {1, -1} },
  233.   { {0, 0}, {1, 1}, {0, 2}, {-1, 1}, {-1, -1}, { 0, -2}, {1, -1} }
  234. };
  235. static XPoint hexagonList[MAXORIENT][7];
  236.  
  237. static void InitializeHexagons(request, new)
  238.   Widget request, new;
  239. {
  240.   HexagonsWidget w = (HexagonsWidget) new;
  241.   XGCValues values;
  242.   XtGCMask valueMask;
  243.  
  244.   w->hexagons.tileOfPosition = NULL;
  245.   CheckTiles(w);
  246.   InitMoves();
  247.   ResetTiles(w);
  248.   (void) SRAND(getpid());
  249.   valueMask = GCForeground | GCBackground;
  250.   values.foreground = w->hexagons.foreground;
  251.   values.background = w->core.background_pixel;
  252.   w->hexagons.puzzleGC = XtGetGC(new, valueMask, &values);
  253.   values.foreground = w->hexagons.tileColor;
  254.   w->hexagons.tileGC = XtGetGC(new, valueMask, &values);
  255.   values.foreground = w->hexagons.borderColor;
  256.   w->hexagons.borderGC = XtGetGC(new, valueMask, &values);
  257.   valueMask = GCForeground | GCBackground;
  258.   values.foreground = w->core.background_pixel;
  259.   values.background = w->hexagons.foreground;
  260.   w->hexagons.inverseGC = XtGetGC(new, valueMask, &values);
  261.   ResizeHexagons(w);
  262. }
  263.  
  264. static void DestroyHexagons(old)
  265.   Widget old;
  266. {
  267.   HexagonsWidget w = (HexagonsWidget) old;
  268.  
  269.   XtReleaseGC(old, w->hexagons.tileGC);
  270.   XtReleaseGC(old, w->hexagons.borderGC);
  271.   XtReleaseGC(old, w->hexagons.puzzleGC);
  272.   XtReleaseGC(old, w->hexagons.inverseGC);
  273.   XtRemoveCallbacks(old, XtNselectCallback, w->hexagons.select);
  274. }
  275.  
  276. static void ResizeHexagons(w)
  277.   HexagonsWidget w;
  278. {
  279.   double sqrt_3 = 1.73205080756887729352744634150587237;
  280.   XPoint tempSize;
  281.  
  282.   w->hexagons.delta.x = 2;
  283.   w->hexagons.delta.y = 2;
  284.   w->hexagons.tileSize.x = MAX((2 * ((int) w->core.width +
  285.     2 * w->hexagons.delta.x - 1) - 4 * w->hexagons.size *
  286.     w->hexagons.delta.x) / (4 * w->hexagons.size - 1), 0);
  287.   w->hexagons.tileSize.y = MAX(((int) w->core.height - 1 -
  288.     2 * w->hexagons.size * w->hexagons.delta.y) /
  289.     (3 * w->hexagons.size - 1), 0);
  290.   w->hexagons.offset.x = w->hexagons.tileSize.x + w->hexagons.delta.x;
  291.   w->hexagons.offset.y = w->hexagons.tileSize.y + 2 * w->hexagons.delta.y;
  292.   tempSize.y = (int) ((double) w->hexagons.offset.x / sqrt_3);
  293.   tempSize.x = (int) ((double) w->hexagons.offset.y * sqrt_3);
  294.   if (tempSize.y <  w->hexagons.offset.y) {
  295.     w->hexagons.offset.x = w->hexagons.tileSize.x + w->hexagons.delta.x;
  296.     w->hexagons.offset.y = tempSize.y;
  297.   } else /* tempSize.x <=  w->hexagons.offset.x */ {
  298.     w->hexagons.offset.x = tempSize.x;
  299.     w->hexagons.offset.y = w->hexagons.tileSize.y + 2 * w->hexagons.delta.y;
  300.   }
  301.   w->hexagons.tileSize.x = MAX(w->hexagons.offset.x - w->hexagons.delta.x, 0);
  302.   w->hexagons.tileSize.y = MAX(w->hexagons.offset.y - 2 * w->hexagons.delta.y,
  303.     0);
  304.   w->hexagons.puzzleSize.x = w->hexagons.size * 2 * w->hexagons.offset.x -
  305.     w->hexagons.tileSize.x / 2 - 2 * w->hexagons.delta.x + 1;
  306.   w->hexagons.puzzleSize.y = w->hexagons.size * (3 * w->hexagons.tileSize.y +
  307.     2 * w->hexagons.delta.y) - w->hexagons.tileSize.y + 2;
  308.   w->hexagons.puzzleOffset.x =
  309.     ((int) w->core.width - w->hexagons.puzzleSize.x + 2) / 2;
  310.   w->hexagons.puzzleOffset.y =
  311.     ((int) w->core.height - w->hexagons.puzzleSize.y + 2) / 2;
  312.   ResizeTiles(w);
  313. }
  314.  
  315. static void ExposeHexagons(new, event, region)
  316.   Widget new;
  317.   XEvent *event;
  318.   Region region; /* Not used */
  319. {
  320.   HexagonsWidget w = (HexagonsWidget) new;
  321.  
  322.   if (w->core.visible) {
  323.     DrawFrame(w, w->hexagons.puzzleGC);
  324.     DrawAllTiles(w, w->hexagons.tileGC, w->hexagons.borderGC);
  325.   }
  326. }
  327.  
  328. static Boolean SetValuesHexagons(current, request, new)
  329.   Widget current, request, new;
  330. {
  331.   HexagonsWidget c = (HexagonsWidget) current, w = (HexagonsWidget) new;
  332.   XGCValues values;
  333.   XtGCMask valueMask;
  334.   Boolean redraw = FALSE;
  335.   Boolean redrawTiles = FALSE;
  336.  
  337.   CheckTiles(w);
  338.   if (w->hexagons.foreground != c->hexagons.foreground) {
  339.     valueMask = GCForeground | GCBackground;
  340.     values.foreground = w->hexagons.foreground;
  341.     values.background = w->core.background_pixel;
  342.     XtReleaseGC(new, w->hexagons.puzzleGC);
  343.     w->hexagons.puzzleGC = XtGetGC(new, valueMask, &values);
  344.     redrawTiles = TRUE;
  345.   }
  346.   if (w->core.background_pixel != c->core.background_pixel) {
  347.     valueMask = GCForeground | GCBackground;
  348.     values.foreground = w->core.background_pixel;
  349.     values.background = w->hexagons.foreground;
  350.     XtReleaseGC(new, w->hexagons.inverseGC);
  351.     w->hexagons.inverseGC = XtGetGC(new, valueMask, &values);
  352.     redrawTiles = TRUE;
  353.   }
  354.   if (w->hexagons.tileColor != c->hexagons.tileColor) {
  355.     valueMask = GCForeground | GCBackground;
  356.     values.foreground = w->hexagons.tileColor;
  357.     values.background = w->core.background_pixel;
  358.     XtReleaseGC(new, w->hexagons.tileGC);
  359.     w->hexagons.tileGC = XtGetGC(new, valueMask, &values);
  360.     redrawTiles = TRUE;
  361.   }
  362.   if (w->hexagons.borderColor != c->hexagons.borderColor) {
  363.     valueMask = GCForeground | GCBackground;
  364.     values.foreground = w->hexagons.borderColor;
  365.     values.background = w->core.background_pixel;
  366.     XtReleaseGC(new, w->hexagons.borderGC);
  367.     w->hexagons.borderGC = XtGetGC(new, valueMask, &values);
  368.     redrawTiles = TRUE;
  369.   }
  370.   if (w->hexagons.size != c->hexagons.size ||
  371.       w->hexagons.corners != c->hexagons.corners ||
  372.       w->hexagons.base != c->hexagons.base) {
  373.     ResetTiles(w);
  374.     ResizeHexagons(w);
  375.     redraw = TRUE;
  376.   }
  377.   else if (w->hexagons.offset.x != c->hexagons.offset.x ||
  378.            w->hexagons.offset.y != c->hexagons.offset.y) {
  379.     ResizeHexagons(w);
  380.     redraw = TRUE;
  381.   }
  382.   if (redrawTiles && !redraw && XtIsRealized(new) && new->core.visible) {
  383.     DrawFrame(c, c->hexagons.inverseGC);
  384.     DrawAllTiles(c, c->hexagons.inverseGC, c->hexagons.inverseGC);
  385.     DrawFrame(w, w->hexagons.puzzleGC);
  386.     DrawAllTiles(w, w->hexagons.tileGC, w->hexagons.borderGC);
  387.   }
  388.   return (redraw);
  389. }
  390.  
  391. static void QuitHexagons(w, event, args, nArgs)
  392.   HexagonsWidget w;
  393.   XEvent *event;
  394.   char *args[];
  395.   int nArgs;
  396. {
  397.   XtCloseDisplay(XtDisplay(w));
  398.   exit(0);
  399. }
  400.  
  401. static void SelectHexagons(w, event, args, nArgs)
  402.   HexagonsWidget w;
  403.   XEvent *event;
  404.   char *args[];
  405.   int nArgs;
  406. {
  407.   int pos, row;
  408.  
  409.   pos = PositionToTile(w, event->xbutton.x, event->xbutton.y, &row);
  410.   if (pos >= 0) {
  411.     if (CheckSolved(w)) {
  412.       MoveNoTiles(w);
  413.       w->hexagons.currentPosition = -1;
  414.       return;
  415.     }
  416.     w->hexagons.currentPosition = PositionFromRow(w, pos, row);
  417.     w->hexagons.currentRow[ROW] = row;
  418.     w->hexagons.currentRow[TRBL] = TrBl(w, w->hexagons.currentPosition, row);
  419.     w->hexagons.currentRow[TLBR] = TlBr(w, w->hexagons.currentPosition, row);
  420.     if (w->hexagons.spacePosition[HIGH] != w->hexagons.currentPosition &&
  421.         (!w->hexagons.corners ||
  422.          w->hexagons.spacePosition[LOW] != w->hexagons.currentPosition))
  423.       DrawTile(w, w->hexagons.borderGC, w->hexagons.tileGC,
  424.         w->hexagons.currentPosition, TRUE);
  425.     else
  426.       w->hexagons.currentPosition = -1;
  427.   } else
  428.     w->hexagons.currentPosition = -1;
  429. }
  430.  
  431. static void ReleaseHexagons(w, event, args, nArgs)
  432.   HexagonsWidget w;
  433.   XEvent *event;
  434.   char *args[];
  435.   int nArgs;
  436. {
  437.   int pos, row, space;
  438.  
  439.   if (w->hexagons.currentPosition == -1)
  440.     return;
  441.   DrawTile(w, w->hexagons.inverseGC, w->hexagons.inverseGC,
  442.     w->hexagons.currentPosition, TRUE);
  443.   DrawTile(w, w->hexagons.tileGC, w->hexagons.borderGC,
  444.     w->hexagons.currentPosition, FALSE);
  445.   if (!w->hexagons.corners) {
  446.     SelectNoCornTiles(w);
  447.     w->hexagons.currentPosition = -1;
  448.     return;
  449.   }
  450.   pos = PositionToTile(w, event->xbutton.x, event->xbutton.y, &row);
  451.   if (pos >= 0) {
  452.     pos = PositionFromRow(w, pos, row);
  453.     if (w->hexagons.spacePosition[HIGH] == pos)
  454.       space = (w->hexagons.spacePosition[HIGH] >
  455.                w->hexagons.spacePosition[LOW]);
  456.     else if (w->hexagons.spacePosition[LOW] == pos)
  457.       space = (w->hexagons.spacePosition[HIGH] <
  458.                w->hexagons.spacePosition[LOW]);
  459.     else {
  460.       w->hexagons.currentPosition = -1;
  461.       return;
  462.     }
  463.     SelectCornerTiles(w, space);
  464.   }
  465.   w->hexagons.currentPosition = -1;
  466. }
  467.  
  468. static void RandomizeHexagons(w, event, args, nArgs)
  469.   HexagonsWidget w;
  470.   XEvent *event;
  471.   char *args[];
  472.   int nArgs;
  473. {
  474.   RandomizeTiles(w);
  475. }
  476.  
  477. static void RandomizeHexagonsMaybe(w, event, args, nArgs)
  478.   HexagonsWidget w;
  479.   XEvent *event;
  480.   char *args[];
  481.   int nArgs;
  482. {
  483.   if (!w->hexagons.started)
  484.     RandomizeTiles(w);
  485. }
  486.  
  487. static void GetHexagons(w, event, args, nArgs)
  488.   HexagonsWidget w;
  489.   XEvent *event;
  490.   char *args[];
  491.   int nArgs;
  492. {
  493.   FILE *fp;
  494.   char c;
  495.   int i, size, corners, moves;
  496.   hexagonsCallbackStruct cb;
  497.  
  498.   if ((fp = fopen(DATAFILE, "r")) == NULL)
  499.     (void) printf("Can not read %s for get.\n", DATAFILE);
  500.   else {
  501.     FlushMoves(w);
  502.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  503.     (void) fscanf(fp, "%d", &size);
  504.     if (size >= MINHEXAGONS) {
  505.       for (i = w->hexagons.size; i < size; i++) {
  506.         cb.reason = HEXAGONS_INC;
  507.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  508.       }
  509.       for (i = w->hexagons.size; i > size; i--) {
  510.         cb.reason = HEXAGONS_DEC;
  511.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  512.       }
  513.     } else
  514.       (void) printf("%s corrupted: size %d should be between %d and MAXINT\n",
  515.          DATAFILE, size, MINHEXAGONS);
  516.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  517.     (void) fscanf(fp, "%d", &corners);
  518.     if (w->hexagons.corners != (Boolean) corners) {
  519.       cb.reason = HEXAGONS_CORNERS;
  520.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  521.     }
  522.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  523.     (void) fscanf(fp, "%d", &moves);
  524.     ScanStartPosition(fp, w);
  525.     cb.reason = HEXAGONS_RESTORE;
  526.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  527.     SetStartPosition(w);
  528.     ScanMoves(fp, w, moves);
  529.     (void) fclose(fp);
  530.     (void) printf("%s: size %d, corners %d, moves %d.\n",
  531.       DATAFILE, size, corners, moves);
  532.   }
  533. }
  534.  
  535. static void WriteHexagons(w, event, args, nArgs)
  536.   HexagonsWidget w;
  537.   XEvent *event;
  538.   char *args[];
  539.   int nArgs;
  540. {
  541.   FILE *fp;
  542.  
  543.   if ((fp = fopen(DATAFILE, "w")) == NULL)
  544.     (void) printf("Can not write to %s.\n", DATAFILE);
  545.   else {
  546.     (void) fprintf(fp, "size%c %d\n", SYMBOL, w->hexagons.size);
  547.     (void) fprintf(fp, "corners%c %d\n", SYMBOL, (w->hexagons.corners) ? 1 : 0);
  548.     (void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
  549.     PrintStartPosition(fp, w);
  550.     PrintMoves(fp);
  551.     (void) fclose(fp);
  552.     (void) printf("Saved to %s.\n", DATAFILE);
  553.   }
  554. }
  555.  
  556. static void UndoHexagons(w, event, args, nArgs)
  557.   HexagonsWidget w;
  558.   XEvent *event;
  559.   char *args[];
  560.   int nArgs;
  561. {
  562.   if (MadeMoves()) {
  563.     int direction;
  564.  
  565.     GetMove(&direction);
  566.     direction = (direction + (COORD / 2)) % COORD;
  567.     if (MoveTilesDir(w, direction)) {
  568.       hexagonsCallbackStruct cb;
  569.  
  570.       cb.reason = HEXAGONS_UNDO;
  571.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  572.     }
  573.   }
  574. }
  575.  
  576. static void SolveHexagons(w, event, args, nArgs)
  577.   HexagonsWidget w;
  578.   XEvent *event;
  579.   char *args[];
  580.   int nArgs;
  581. {
  582.   /* SolveTiles(w); */ /* Sorry, unimplemented */
  583. }
  584.  
  585. static void IncrementHexagons(w, event, args, nArgs)
  586.   HexagonsWidget w;
  587.   XEvent *event;
  588.   char *args[];
  589.   int nArgs;
  590. {
  591.   hexagonsCallbackStruct cb;
  592.  
  593.   cb.reason = HEXAGONS_INC;
  594.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  595. }
  596.  
  597. static void DecrementHexagons(w, event, args, nArgs)
  598.   HexagonsWidget w;
  599.   XEvent *event;
  600.   char *args[];
  601.   int nArgs;
  602. {
  603.   hexagonsCallbackStruct cb;
  604.  
  605.   if (w->hexagons.size <= MINHEXAGONS)
  606.     return;
  607.   cb.reason = HEXAGONS_DEC;
  608.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  609. }
  610.  
  611. static void CornerHexagons(w, event, args, nArgs)
  612.   HexagonsWidget w;
  613.   XEvent *event;
  614.   char *args[];
  615.   int nArgs;
  616. {
  617.   hexagonsCallbackStruct cb;
  618.  
  619.   cb.reason = HEXAGONS_CORNERS;
  620.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  621. }
  622.  
  623. static void MoveHexagonsTl(w, event, args, nArgs)
  624.   HexagonsWidget w;
  625.   XEvent *event;
  626.   char *args[];
  627.   int nArgs;
  628. {
  629.   (void) MoveHexagons(w, TL);
  630. }
  631.  
  632. static void MoveHexagonsTr(w, event, args, nArgs)
  633.   HexagonsWidget w;
  634.   XEvent *event;
  635.   char *args[];
  636.   int nArgs;
  637. {
  638.   (void) MoveHexagons(w, TR);
  639. }
  640.  
  641. static void MoveHexagonsLeft(w, event, args, nArgs)
  642.   HexagonsWidget w;
  643.   XEvent *event;
  644.   char *args[];
  645.   int nArgs;
  646. {
  647.   (void) MoveHexagons(w, LEFT);
  648. }
  649.  
  650. static void MoveHexagonsRight(w, event, args, nArgs)
  651.   HexagonsWidget w;
  652.   XEvent *event;
  653.   char *args[];
  654.   int nArgs;
  655. {
  656.   (void) MoveHexagons(w, RIGHT);
  657. }
  658.  
  659. static void MoveHexagonsBl(w, event, args, nArgs)
  660.   HexagonsWidget w;
  661.   XEvent *event;
  662.   char *args[];
  663.   int nArgs;
  664. {
  665.   (void) MoveHexagons(w, BL);
  666. }
  667.  
  668. static void MoveHexagonsBr(w, event, args, nArgs)
  669.   HexagonsWidget w;
  670.   XEvent *event;
  671.   char *args[];
  672.   int nArgs;
  673. {
  674.   (void) MoveHexagons(w, BR);
  675. }
  676.  
  677. static int MoveHexagons(w, direction)
  678.   HexagonsWidget w;
  679.   int direction;
  680. {
  681.   hexagonsCallbackStruct cb;
  682.  
  683.   if (CheckSolved(w)) {
  684.     MoveNoTiles(w);
  685.     return FALSE;
  686.   }
  687.   if (!MoveHexagonsDir(w, direction)) {
  688.     cb.reason = HEXAGONS_BLOCKED;
  689.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  690.     return FALSE;
  691.   }
  692.   if (CheckSolved(w)) {
  693.     cb.reason = HEXAGONS_SOLVED;
  694.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  695.   }
  696.   return TRUE;
  697. }
  698.  
  699. int MoveHexagonsDir(w, direction)
  700.   HexagonsWidget w;
  701.   int direction;
  702. {
  703.   hexagonsCallbackStruct cb;
  704.  
  705.   if (MoveTilesDir(w, direction)) {
  706.     cb.reason = HEXAGONS_MOVED;
  707.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  708.     PutMove(direction);
  709.     return TRUE;
  710.   }
  711.   return FALSE;
  712. }
  713.  
  714. static int PositionToTile(w, x, y, row)
  715.   HexagonsWidget w;
  716.   int x, y;
  717.   int *row;
  718. {
  719.   int i, j, k, modI, modJ;
  720.  
  721.   x -= w->hexagons.puzzleOffset.x;
  722.   y -= w->hexagons.puzzleOffset.y;
  723.   /* First convert x and y coordinates to hexagon grid.  Keep in mind that
  724.        the starting hexagon x position changes with "w->hexagons.size % 2". */
  725.   if (x < w->hexagons.tileSize.x / 4)
  726.     return -1;
  727.   i = 2 * (x - w->hexagons.tileSize.x / 4) / w->hexagons.offset.x;
  728.   j = 3 * (y - w->hexagons.delta.y) /
  729.     (3 * w->hexagons.tileSize.y / 2 + w->hexagons.delta.y);
  730.   modI = 2 * (x - w->hexagons.tileSize.x / 4) % w->hexagons.offset.x;
  731.   modJ = 3 * (y - w->hexagons.delta.y) %
  732.    (3 * w->hexagons.tileSize.y / 2 + w->hexagons.delta.y);
  733.   *row = j / 3; /* Approximate to a rectangle just for now */
  734.   if (j % 3 == 0) /* Then it is the triangle near bottom or top point */ {
  735.     if ((w->hexagons.size - 1 + *row + i) % 2) /* \ */ 
  736.       *row -= (modJ * w->hexagons.offset.x < modI *
  737.           (3 * w->hexagons.tileSize.y / 2 + w->hexagons.delta.y));
  738.     else /* / */ 
  739.       *row -= (modJ * w->hexagons.offset.x < (w->hexagons.offset.x - modI) *
  740.           (3 * w->hexagons.tileSize.y / 2 + w->hexagons.delta.y));
  741.   }
  742.   if (i < (w->hexagons.size - 1 + *row) % 2 || *row < 0 ||
  743.       *row > 2 * (w->hexagons.size - 1)) 
  744.     return -1;
  745.   k = (i - ((w->hexagons.size - 1 + *row) % 2)) / 2;
  746.   /* Map the hexagon grid to hexagon position in puzzle. */
  747.   i = (*row < w->hexagons.size) ?
  748.     k - (w->hexagons.size - 1 - *row) / 2:
  749.     k + (w->hexagons.size - 1 - *row) / 2;
  750.   j = (*row < w->hexagons.size) ?
  751.     w->hexagons.size - 1 + *row : 3 * (w->hexagons.size - 1) - *row;
  752.   if  (i < 0 || i > j)
  753.     return -1;
  754.   return i;
  755. }
  756.  
  757. static void SelectCornerTiles(w, space)
  758.   HexagonsWidget w;
  759.   int space;
  760. {
  761.   int orient;
  762.   hexagonsCallbackStruct cb;
  763.  
  764.   /* Are the spaces in a "row" with the mouse click?
  765.   (If two, then one clicked on a space).*/
  766.   if (w->hexagons.currentPosition == w->hexagons.spacePosition[LOW] ||
  767.       w->hexagons.currentPosition == w->hexagons.spacePosition[HIGH]) {
  768.     cb.reason = HEXAGONS_SPACE;
  769.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  770.     return;
  771.   }
  772.   if (FindTileTriangle(w,
  773.        w->hexagons.currentPosition, w->hexagons.spacePosition[HIGH],
  774.        w->hexagons.spacePosition[LOW], w->hexagons.currentRow[ROW],
  775.        w->hexagons.spaceRow[HIGH], w->hexagons.spaceRow[LOW]))
  776.   {
  777.     orient = (w->hexagons.spacePosition[HIGH] <
  778.       w->hexagons.spacePosition[LOW]) ? !space : space;
  779.     PutMove(FindDir(w,
  780.        w->hexagons.currentPosition, w->hexagons.spacePosition[orient],
  781.        w->hexagons.currentRow[ROW], w->hexagons.spaceRow[orient]));
  782.     MoveCornerTiles(w, w->hexagons.currentPosition,
  783.       w->hexagons.currentRow[ROW], orient);
  784.     cb.reason = HEXAGONS_MOVED;
  785.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  786.   } else {
  787.     cb.reason = HEXAGONS_BLOCKED;
  788.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  789.     return;
  790.   }
  791.   if (CheckSolved(w)) {
  792.     cb.reason = HEXAGONS_SOLVED;
  793.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  794.   }
  795. }
  796.  
  797. static void SelectNoCornTiles(w)
  798.   HexagonsWidget w;
  799. {
  800.   hexagonsCallbackStruct cb;
  801.   int rowType = -1, l, orient;
  802.  
  803.   /* Are the spaces in a "row" with the mouse click?
  804.   (If two, then one clicked on a space).*/
  805.   for (l = 0; l < ROWTYPES; l++)
  806.     if (w->hexagons.currentRow[l] == w->hexagons.spaceRow[l]) {
  807.       if (rowType == -1)
  808.         rowType = l;
  809.       else {
  810.         cb.reason = HEXAGONS_SPACE;
  811.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  812.         return;
  813.       }
  814.     }
  815.   if (rowType != -1) {
  816.     if (w->hexagons.currentPosition < w->hexagons.spacePosition[HIGH]) {
  817.       while (w->hexagons.currentPosition < w->hexagons.spacePosition[HIGH]) {
  818.         orient = (rowType == ROW) ?
  819.           w->hexagons.spaceRow[ROW] : w->hexagons.spaceRow[ROW] - 1;
  820.         MoveNoCornTiles(w, TileNextToSpace(w, rowType, HIGH), orient);
  821.         cb.reason = HEXAGONS_MOVED;
  822.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  823.         switch (rowType) {
  824.           case TLBR:
  825.             PutMove(BR);
  826.             break;
  827.           case TRBL:
  828.             PutMove(BL);
  829.             break;
  830.           case ROW:
  831.             PutMove(RIGHT);
  832.             break;
  833.           default:
  834.             (void) printf ("SelectNoCornTiles: rowType %d\n", rowType);
  835.         }
  836.       }
  837.     } else /*w->hexagons.currentPosition > w->hexagons.spacePosition[HIGH]*/ {
  838.       while (w->hexagons.currentPosition > w->hexagons.spacePosition[HIGH]) {
  839.         orient = (rowType == ROW) ?
  840.           w->hexagons.spaceRow[ROW] : w->hexagons.spaceRow[ROW] + 1;
  841.         MoveNoCornTiles(w, TileNextToSpace(w, rowType, LOW), orient);
  842.         cb.reason = HEXAGONS_MOVED;
  843.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  844.         switch (rowType) {
  845.           case TLBR:
  846.             PutMove(TL);
  847.             break;
  848.           case TRBL:
  849.             PutMove(TR);
  850.             break;
  851.           case ROW:
  852.             PutMove(LEFT);
  853.             break;
  854.           default:
  855.             (void) printf ("SelectNoCornTiles: rowType %d\n", rowType);
  856.         }
  857.       }
  858.     }
  859.   } else {
  860.     cb.reason = HEXAGONS_BLOCKED;
  861.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  862.     return;
  863.   }
  864.   if (CheckSolved(w)) {
  865.     cb.reason = HEXAGONS_SOLVED;
  866.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  867.   }
  868. }
  869.  
  870. static void CheckTiles(w)
  871.   HexagonsWidget w;
  872. {
  873.   char buf[121];
  874.  
  875.   if (w->hexagons.size < MINHEXAGONS) {
  876.     (void) sprintf(buf,
  877.              "Number of Hexagons on a edge out of bounds, use %d..MAXINT",
  878.              MINHEXAGONS);
  879.     XtWarning(buf);
  880.     w->hexagons.size = DEFAULTHEXAGONS;
  881.   }
  882.   w->hexagons.base = 10;
  883. }
  884.  
  885. static void ResetTiles(w)
  886.   HexagonsWidget w;
  887. {
  888.   int i;
  889.  
  890.   w->hexagons.sizeSize = 3 * w->hexagons.size * (w->hexagons.size - 1) + 1;
  891.   w->hexagons.sizeCenter = (w->hexagons.sizeSize - 1) / 2;
  892.   if (w->hexagons.tileOfPosition)
  893.     (void) free((void *) w->hexagons.tileOfPosition);
  894.   if (!(w->hexagons.tileOfPosition = (int *)
  895.         malloc(sizeof(int) * w->hexagons.sizeSize)))
  896.     XtError("Not enough memory, exiting.");
  897.   if (startPosition)
  898.     (void) free((void *) startPosition);
  899.   if (!(startPosition = (int *)
  900.         malloc(sizeof(int) * w->hexagons.sizeSize)))
  901.     XtError("Not enough memory, exiting.");
  902.   w->hexagons.spacePosition[HIGH] = w->hexagons.sizeSize - 1;
  903.   if (w->hexagons.corners) {
  904.     w->hexagons.spaceRow[HIGH] = 2 * w->hexagons.size - 2;
  905.     if (w->hexagons.size > 1) {
  906.       w->hexagons.spacePosition[LOW] = w->hexagons.sizeSize - 2;
  907.       w->hexagons.spaceRow[LOW] = 2 * w->hexagons.size - 2;
  908.       w->hexagons.tileOfPosition[w->hexagons.sizeSize - 2] = -1;
  909.     }
  910.   } else {
  911.     w->hexagons.spaceRow[ROW] = w->hexagons.spaceRow[TRBL] =
  912.       2 * w->hexagons.size - 2;
  913.     w->hexagons.spaceRow[TLBR] = w->hexagons.size - 1;
  914.   }
  915.   w->hexagons.tileOfPosition[w->hexagons.sizeSize - 1] = 0;
  916.   for (i = 1; i < w->hexagons.sizeSize - ((w->hexagons.corners) ? 1 : 0);
  917.        i++)
  918.     w->hexagons.tileOfPosition[i - 1] = i;
  919.   FlushMoves(w);
  920.   w->hexagons.currentPosition = -1;
  921.   w->hexagons.started = FALSE;
  922. }
  923.  
  924. static void ResizeTiles(w)
  925.   HexagonsWidget w;
  926. {
  927.   int i;
  928.  
  929.   for (i = 0; i <= 6; i++) { 
  930.     hexagonList[NOCORN][i].x = w->hexagons.tileSize.x *
  931.       hexagonUnit[NOCORN][i].x / 4;
  932.     hexagonList[NOCORN][i].y = 3 * w->hexagons.tileSize.y *
  933.       hexagonUnit[NOCORN][i].y / 4;
  934.     hexagonList[CORNERS][i].x = w->hexagons.tileSize.x *
  935.       hexagonUnit[CORNERS][i].x / 2;
  936.     hexagonList[CORNERS][i].y = w->hexagons.tileSize.y *
  937.       hexagonUnit[CORNERS][i].y / 2;
  938.   }
  939.   w->hexagons.digitOffset.x = 3;
  940.   w->hexagons.digitOffset.y = 4;
  941. }
  942.  
  943. static int MovableCornerTiles(w, direction, position, posRow, space)
  944.   HexagonsWidget w;
  945.   int direction, *position, *posRow, *space;
  946. {
  947.   int spaceType, highest, side = -1;
  948.  
  949.   highest = (w->hexagons.spacePosition[HIGH] >
  950.     w->hexagons.spacePosition[LOW]) ? HIGH : LOW;
  951.   spaceType = FindSpaceType(w, 
  952.     w->hexagons.spacePosition[HIGH], w->hexagons.spacePosition[LOW],
  953.     w->hexagons.spaceRow[HIGH], w->hexagons.spaceRow[LOW]);
  954.   switch (spaceType) {
  955.     case TRBL:
  956.       if (direction == TR || direction == BL)
  957.         return FALSE;
  958.       side = NextToWall(w, w->hexagons.spacePosition[highest],
  959.       w->hexagons.spaceRow[highest], spaceType);
  960.       if (side != -1)
  961.       {
  962.         if ((side == HIGH && direction == RIGHT) ||
  963.             (side == HIGH && direction == BR) ||
  964.             (side == LOW && direction == LEFT) ||
  965.             (side == LOW && direction == TL))
  966.           return FALSE;
  967.       } else
  968.         side = (direction == TL || direction == LEFT);
  969.       *space = (direction == BR || direction == LEFT);
  970.       break;
  971.     case TLBR:
  972.       if (direction == TL || direction == BR)
  973.         return FALSE;
  974.       side = NextToWall(w, w->hexagons.spacePosition[highest],
  975.       w->hexagons.spaceRow[highest], spaceType);
  976.       if (side != -1) {
  977.         if ((side == LOW && direction == TR) ||
  978.             (side == LOW && direction == RIGHT) ||
  979.             (side == HIGH && direction == BL) ||
  980.             (side == HIGH && direction == LEFT))
  981.           return FALSE;
  982.       } else
  983.         side = (direction == TR || direction == RIGHT);
  984.       *space = (direction == RIGHT || direction == BL);
  985.       break;
  986.     case ROW:
  987.       if (direction == LEFT || direction == RIGHT)
  988.         return FALSE;
  989.       side = NextToWall(w, w->hexagons.spacePosition[highest],
  990.       w->hexagons.spaceRow[highest], spaceType);
  991.       if (side != -1) {
  992.         if ((side == LOW && direction == TR) ||
  993.             (side == HIGH && direction == BR) ||
  994.             (side == HIGH && direction == BL) ||
  995.             (side == LOW && direction == TL))
  996.           return FALSE;
  997.       } else
  998.         side = (direction == TR || direction == TL);
  999.       *space = (direction == TR || direction == BR);
  1000.       break;
  1001.   }
  1002.   FindMovableTile(w, w->hexagons.spacePosition[highest],
  1003.     w->hexagons.spaceRow[highest], spaceType, side, position, posRow);
  1004.   return TRUE;
  1005. }
  1006.  
  1007. static void MoveNoTiles(w)
  1008.   HexagonsWidget w;
  1009. {
  1010.   hexagonsCallbackStruct cb;
  1011.  
  1012.   cb.reason = HEXAGONS_IGNORE;
  1013.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1014. }
  1015.  
  1016. static int MoveTilesDir(w, direction)
  1017.   HexagonsWidget w;
  1018.   int direction;
  1019. {
  1020.   if (w->hexagons.corners)
  1021.     return MoveCornerTilesDir(w, direction);
  1022.   else
  1023.     return MoveNoCornTilesDir(w, direction);
  1024. }
  1025.  
  1026.  
  1027. static int MoveCornerTilesDir(w, direction)
  1028.   HexagonsWidget w;
  1029.   int direction;
  1030. {
  1031.   int position, posRow, space;
  1032.   
  1033.   if (MovableCornerTiles(w, direction, &position, &posRow, &space)) {
  1034.     MoveCornerTiles(w, position, posRow, (w->hexagons.spacePosition[HIGH] <
  1035.       w->hexagons.spacePosition[LOW]) ? !space : space);
  1036.     return TRUE;
  1037.   }
  1038.   return FALSE;
  1039. }
  1040.  
  1041. static int MoveNoCornTilesDir(w, direction)
  1042.   HexagonsWidget w;
  1043.   int direction;
  1044. {
  1045.   switch (direction) {
  1046.     case TR:
  1047.       if (w->hexagons.spaceRow[ROW] != 2 * w->hexagons.size - 2 &&
  1048.           w->hexagons.spaceRow[TLBR] != 2 * w->hexagons.size - 2) {
  1049.         MoveNoCornTiles(w, TileNextToSpace(w, TRBL, LOW),
  1050.           w->hexagons.spaceRow[ROW] + 1);
  1051.         return TRUE;
  1052.       }
  1053.       break;
  1054.     case RIGHT:
  1055.       if (w->hexagons.spaceRow[TRBL] != 0 &&
  1056.           w->hexagons.spaceRow[TLBR] != 2 * w->hexagons.size - 2) {
  1057.         MoveNoCornTiles(w, TileNextToSpace(w, ROW, HIGH),
  1058.           w->hexagons.spaceRow[ROW]);
  1059.         return TRUE;
  1060.       }
  1061.       break;
  1062.     case BR:
  1063.       if (w->hexagons.spaceRow[ROW] != 0 &&
  1064.           w->hexagons.spaceRow[TRBL] != 0) {
  1065.         MoveNoCornTiles(w, TileNextToSpace(w, TLBR, HIGH),
  1066.           w->hexagons.spaceRow[ROW] - 1);
  1067.         return TRUE;
  1068.       }
  1069.       break;
  1070.     case BL:
  1071.       if (w->hexagons.spaceRow[ROW] != 0 &&
  1072.           w->hexagons.spaceRow[TLBR] != 0) {
  1073.         MoveNoCornTiles(w, TileNextToSpace(w, TRBL, HIGH),
  1074.           w->hexagons.spaceRow[ROW] - 1);
  1075.         return TRUE;
  1076.       }
  1077.       break;
  1078.     case LEFT:
  1079.       if (w->hexagons.spaceRow[TLBR] != 0 &&
  1080.           w->hexagons.spaceRow[TRBL] != 2 * w->hexagons.size - 2) {
  1081.         MoveNoCornTiles(w, TileNextToSpace(w, ROW, LOW),
  1082.           w->hexagons.spaceRow[ROW]);
  1083.         return TRUE;
  1084.       }
  1085.       break;
  1086.     case TL:
  1087.       if (w->hexagons.spaceRow[ROW] != 2 * w->hexagons.size - 2 &&
  1088.           w->hexagons.spaceRow[TRBL] != 2 * w->hexagons.size - 2) {
  1089.         MoveNoCornTiles(w, TileNextToSpace(w, TLBR, LOW),
  1090.           w->hexagons.spaceRow[ROW] + 1);
  1091.         return TRUE;
  1092.       }
  1093.       break;
  1094.     default:
  1095.       (void) printf("MoveNoCornTilesDir: direction %d\n", direction);
  1096.   }
  1097.   return FALSE;
  1098. }
  1099.  
  1100. static void RandomizeTiles(w)
  1101.   HexagonsWidget w;
  1102. {
  1103.   hexagonsCallbackStruct cb;
  1104.  
  1105.   /* First interchange tiles an even number of times */
  1106.   if (w->hexagons.size > 1 + ((w->hexagons.corners) ? 1 : 0)) {
  1107.     int currentPos, randomPos;
  1108.     int count = 0;
  1109.  
  1110.     for (currentPos = 0; currentPos < w->hexagons.sizeSize; currentPos++) {
  1111.       randomPos = currentPos;
  1112.       while (currentPos == randomPos)
  1113.         randomPos = NRAND(w->hexagons.sizeSize);
  1114.       count += ExchangeTiles(w, currentPos, randomPos);
  1115.     }
  1116.     if (count % 2 && w->hexagons.corners)
  1117.       if (!ExchangeTiles(w, 0, 1))
  1118.         if (!ExchangeTiles(w,
  1119.             w->hexagons.sizeSize - 2, w->hexagons.sizeSize - 1))
  1120.           (void) printf("RandomizeTiles: should not get here\n");
  1121.     DrawAllTiles(w, w->hexagons.tileGC, w->hexagons.borderGC);
  1122.   }
  1123.   /* Now move the spaces around randomly */
  1124.   if (w->hexagons.size > 1) {
  1125.     int big = w->hexagons.sizeSize + NRAND(2);
  1126.     int lastDirection = 0;
  1127.     int randomDirection;
  1128.  
  1129.     cb.reason = HEXAGONS_RESET;
  1130.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1131.  
  1132.     if (w->hexagons.corners && w->hexagons.size == 2)
  1133.       big *= big;
  1134.  
  1135. #ifdef DEBUG
  1136.     big = 3;
  1137. #endif
  1138.  
  1139.     if (big > 1000)
  1140.       big = 1000;
  1141.     while (big--) {
  1142.       randomDirection = NRAND(COORD);
  1143.  
  1144. #ifdef DEBUG
  1145.       sleep(1);
  1146. #endif
  1147.  
  1148.       if ((randomDirection + COORD / 2) % COORD != lastDirection) {
  1149.         if (MoveHexagonsDir(w, randomDirection))
  1150.           lastDirection = randomDirection;
  1151.         else
  1152.           big++;
  1153.       }
  1154.     }
  1155.     FlushMoves(w);
  1156.     cb.reason = HEXAGONS_RANDOMIZE;
  1157.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1158.   }
  1159.   if (CheckSolved(w)) {
  1160.     cb.reason = HEXAGONS_SOLVED;
  1161.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1162.   }
  1163. }
  1164.  
  1165. static void MoveCornerTiles(w, from, posRow, space)
  1166.   HexagonsWidget w;
  1167.   int from, posRow, space;
  1168. {
  1169.   int tempTile;
  1170.  
  1171.   tempTile = w->hexagons.tileOfPosition[from];
  1172.   w->hexagons.tileOfPosition[from] =
  1173.     w->hexagons.tileOfPosition[w->hexagons.spacePosition[space]];
  1174.   w->hexagons.tileOfPosition[w->hexagons.spacePosition[space]] =
  1175.     tempTile;
  1176.   DrawTile(w, w->hexagons.tileGC, w->hexagons.borderGC,
  1177.     w->hexagons.spacePosition[space], FALSE);
  1178.   w->hexagons.spacePosition[space] = from;
  1179.   w->hexagons.spaceRow[space] = posRow;
  1180.   DrawTile(w, w->hexagons.inverseGC, w->hexagons.inverseGC,
  1181.    w->hexagons.spacePosition[space], FALSE);
  1182. }
  1183.  
  1184. static void MoveNoCornTiles(w, from, posRow)
  1185.   HexagonsWidget w;
  1186.   int from, posRow;
  1187. {
  1188.   int tempTile;
  1189.  
  1190.   tempTile = w->hexagons.tileOfPosition[from];
  1191.   w->hexagons.tileOfPosition[from] =
  1192.      w->hexagons.tileOfPosition[w->hexagons.spacePosition[HIGH]];
  1193.   w->hexagons.tileOfPosition[w->hexagons.spacePosition[HIGH]] = tempTile;
  1194.   DrawTile(w, w->hexagons.tileGC, w->hexagons.borderGC,
  1195.     w->hexagons.spacePosition[HIGH], FALSE);
  1196.   w->hexagons.spacePosition[HIGH] = from;
  1197.   w->hexagons.spaceRow[ROW] = posRow;
  1198.   w->hexagons.spaceRow[TRBL] = TrBl(w, from, posRow);
  1199.   w->hexagons.spaceRow[TLBR] = TlBr(w, from, posRow);
  1200.   DrawTile(w, w->hexagons.inverseGC, w->hexagons.inverseGC,
  1201.     w->hexagons.spacePosition[HIGH], FALSE);
  1202. }
  1203.  
  1204. static int ExchangeTiles(w, pos1, pos2)
  1205.   HexagonsWidget w;
  1206.   int pos1, pos2;
  1207. {
  1208.   int tempTile;
  1209.  
  1210.   if (w->hexagons.tileOfPosition[pos1] <= 0 ||
  1211.       w->hexagons.tileOfPosition[pos2] <= 0)
  1212.     return FALSE;
  1213.   tempTile = w->hexagons.tileOfPosition[pos1];
  1214.   w->hexagons.tileOfPosition[pos1] = w->hexagons.tileOfPosition[pos2];
  1215.   w->hexagons.tileOfPosition[pos2] = tempTile;
  1216.   return TRUE;
  1217. }
  1218.  
  1219. #ifdef DEBUG
  1220. static int WithinFrame(w, x, y, dx, dy)
  1221.   HexagonsWidget w;
  1222.   int x, y, dx, dy;
  1223. {
  1224.   return
  1225.     (x < dx + w->hexagons.tileSize.x / 2 &&
  1226.      x > dx - w->hexagons.tileSize.x / 2 &&
  1227.      w->hexagons.tileSize.y * (x - dx) < w->hexagons.tileSize.x * (y - dy) &&
  1228.      w->hexagons.tileSize.y * (dx - x) < w->hexagons.tileSize.x * (y - dy) &&
  1229.      w->hexagons.tileSize.y * (x - dx + 2 * w->hexagons.tileSize.x) >
  1230.        w->hexagons.tileSize.x * (y - dy) &&
  1231.      w->hexagons.tileSize.y * (dx - x + 2 * w->hexagons.tileSize.x) >
  1232.        w->hexagons.tileSize.x * (y - dy));
  1233. }
  1234. #endif
  1235.  
  1236. static int NextToWall(w, pos, posRow, spaceType)
  1237.   HexagonsWidget w;
  1238.   int pos, posRow, spaceType;
  1239. {
  1240.   switch (spaceType) {
  1241.     case TRBL:
  1242.       if (posRow < w->hexagons.size  && pos ==
  1243.           w->hexagons.size * posRow + posRow * (posRow - 1) / 2)
  1244.         return (HIGH);
  1245.       else if (posRow >= w->hexagons.size && pos == w->hexagons.size *
  1246.           (posRow - w->hexagons.size) + 3 * w->hexagons.size - posRow -
  1247.           2 + 4 * w->hexagons.size * (w->hexagons.size - 1) / 2 -
  1248.           (2 * w->hexagons.size - posRow - 2) *
  1249.           (2 * w->hexagons.size - posRow - 1) / 2)
  1250.         return (LOW);
  1251.       else
  1252.         return (-1);
  1253.     case TLBR:
  1254.       if (posRow < w->hexagons.size && pos ==
  1255.           w->hexagons.size * (posRow + 1) + posRow * (posRow + 1) / 2 - 1)
  1256.         return (HIGH);
  1257.       else if (posRow >= w->hexagons.size && pos == w->hexagons.size *
  1258.           (posRow - w->hexagons.size) + 1 + 4 * w->hexagons.size *
  1259.           (w->hexagons.size - 1) / 2 - (2 * w->hexagons.size - posRow - 2) *
  1260.           (2 * w->hexagons.size - posRow - 1) / 2)
  1261.         return (LOW);
  1262.       else
  1263.         return (-1);
  1264.     case ROW:
  1265.       if (posRow == 0)
  1266.         return (HIGH);
  1267.       else if (posRow == 2 * (w->hexagons.size - 1))
  1268.         return (LOW);
  1269.       else
  1270.         return (-1);
  1271.   }
  1272.   return (-2); /*Unknown space formation.*/
  1273. }
  1274.  
  1275. static int TileNextToSpace(w, rowType, direction)
  1276.   HexagonsWidget w;
  1277.   int rowType, direction;
  1278. {
  1279.   if (direction == HIGH) {
  1280.     if (rowType == TRBL)
  1281.       return ((w->hexagons.spaceRow[ROW] < w->hexagons.size) ?
  1282.         w->hexagons.spacePosition[HIGH] - w->hexagons.size -
  1283.           w->hexagons.spaceRow[ROW] + 1 :
  1284.         w->hexagons.spacePosition[HIGH]- 3 * w->hexagons.size +
  1285.           w->hexagons.spaceRow[ROW] + 2);
  1286.     else if (rowType == TLBR)
  1287.       return ((w->hexagons.spaceRow[ROW] < w->hexagons.size) ?
  1288.              w->hexagons.spacePosition[HIGH] - w->hexagons.size -
  1289.                w->hexagons.spaceRow[ROW] :
  1290.              w->hexagons.spacePosition[HIGH] - 3 * w->hexagons.size +
  1291.                w->hexagons.spaceRow[ROW] + 1);
  1292.     else /* rowType == ROW */
  1293.       return (w->hexagons.spacePosition[HIGH] - 1);
  1294.   } else /* direction == LOW */ {
  1295.     if (rowType == TRBL)
  1296.       return ((w->hexagons.spaceRow[ROW] < w->hexagons.size - 1) ?
  1297.         w->hexagons.spacePosition[HIGH] + w->hexagons.size +
  1298.           w->hexagons.spaceRow[ROW] :
  1299.         w->hexagons.spacePosition[HIGH] + 3 * w->hexagons.size -
  1300.           w->hexagons.spaceRow[ROW] - 3);
  1301.     else if (rowType == TLBR)
  1302.       return ((w->hexagons.spaceRow[ROW] < w->hexagons.size - 1) ?
  1303.         w->hexagons.spacePosition[HIGH] + w->hexagons.size +
  1304.           w->hexagons.spaceRow[ROW] + 1 :
  1305.         w->hexagons.spacePosition[HIGH]+ 3 * w->hexagons.size -
  1306.           w->hexagons.spaceRow[ROW] - 2);
  1307.     else /* rowType == ROW */
  1308.       return (w->hexagons.spacePosition[HIGH] + 1);
  1309.   }
  1310. }
  1311.  
  1312. static int FindTileTriangle(w, pI, pJ, pK, rI, rJ, rK)
  1313.   HexagonsWidget w;
  1314.   int pI, pJ, pK, rI, rJ, rK;
  1315. {
  1316.   int found = TRUE, temp = 0, k = 0, row1 = 0, row2 = 0, pos;
  1317.  
  1318.   if (rI == rJ) {
  1319.     if (pI == pJ - 1)
  1320.       temp = pJ;
  1321.     else if (pI == pJ + 1)
  1322.       temp = pI;
  1323.     else
  1324.       found = FALSE;
  1325.     k = pK;
  1326.     row1 = rI;
  1327.     row2 = rK;
  1328.   } else if (rJ == rK) {
  1329.     if (pJ == pK - 1)
  1330.       temp = pK;
  1331.     else if (pJ == pK + 1)
  1332.       temp = pJ;
  1333.     else
  1334.       found = FALSE;
  1335.     k = pI;
  1336.     row1 = rJ;
  1337.     row2 = rI;
  1338.   } else if (rK == rI) {
  1339.     if (pK == pI - 1)
  1340.       temp = pI;
  1341.     else if (pK == pI + 1)
  1342.       temp = pK;
  1343.     else
  1344.       found = FALSE;
  1345.     k = pJ;
  1346.     row1 = rK;
  1347.     row2 = rJ;
  1348.   }
  1349.   if (found == FALSE)
  1350.     return (0);
  1351.   pos = -1;
  1352.   if (row1 == row2 + 1) {
  1353.     if (row1 <= w->hexagons.size - 1)
  1354.       pos = temp - w->hexagons.size - row1;
  1355.     else /* row1 > w->hexagons.size - 1 */
  1356.       pos = temp - 3 * w->hexagons.size + row1 + 1;
  1357.   } else if (row1 == row2 - 1) {
  1358.     if (row1 < w->hexagons.size - 1)
  1359.       pos = temp + w->hexagons.size + row1;
  1360.     else /* row1 >= w->hexagons.size - 1 */
  1361.       pos = temp + 3 * (w->hexagons.size - 1) - row1;
  1362.   }
  1363.   if (k == pos)
  1364.     return (1);
  1365.   return (0);
  1366. }
  1367.  
  1368. static int FindDir(w, posTile, posSpace, rowTile, rowSpace)
  1369.   HexagonsWidget w;
  1370.   int posTile, posSpace, rowTile, rowSpace;
  1371. {
  1372.   if (rowTile == rowSpace) {
  1373.     if (posTile > posSpace)
  1374.       return LEFT;
  1375.     else
  1376.       return RIGHT; 
  1377.   } else if (TrBl(w, posTile, rowTile) == TrBl(w, posSpace, rowSpace)) {
  1378.     if (posTile > posSpace)
  1379.       return TR;
  1380.     else
  1381.       return BL; 
  1382.   }  else {
  1383.     /* if (TlBr(w, posTile, rowTile) == TlBr(w, posSpace, rowSpace)) */
  1384.     if (posTile > posSpace)
  1385.       return TL;
  1386.     else
  1387.       return BR;
  1388.   }
  1389. }
  1390.  
  1391. static int FindSpaceType(w, pos1, pos2, row1, row2)
  1392.   HexagonsWidget w;
  1393.   int pos1, pos2, row1, row2;
  1394. {
  1395.   if (row1 == row2 && (pos1 == pos2 + 1 || pos1 == pos2 - 1))
  1396.     return (ROW);
  1397.   else if (row1 == row2 - 1) {
  1398.     swap(&row1, &row2);
  1399.     swap(&pos1, &pos2);
  1400.   }
  1401.   if (row1 == row2 + 1) {
  1402.     if (row1 <= w->hexagons.size - 1) {
  1403.       if (pos2 == pos1 - w->hexagons.size - row1)
  1404.         return (TLBR);
  1405.       else if (pos2 == pos1 - w->hexagons.size - row1 + 1)
  1406.         return (TRBL);
  1407.     } else /* row1 > w->hexagons.size - 1 */ {
  1408.       if (pos2 == pos1 - 3 * w->hexagons.size + row1 + 1)
  1409.         return (TLBR);
  1410.       else if (pos2 == pos1 - 3 * w->hexagons.size + row1 + 2)
  1411.         return (TRBL);
  1412.     }
  1413.   }
  1414.   return (-1);
  1415. }
  1416.  
  1417. static void FindMovableTile(w,
  1418.     pos, posRow, spaceType, side, tilePos, tileRow)
  1419.   HexagonsWidget w;
  1420.   int pos, posRow, spaceType, side, *tilePos, *tileRow;
  1421. {
  1422.   switch (spaceType) {
  1423.     case TRBL:
  1424.       if (side == HIGH) {
  1425.         *tileRow = posRow;
  1426.         *tilePos = pos + 1;
  1427.       } else /* side == LOW */ {
  1428.         *tileRow = posRow - 1;
  1429.         *tilePos = (posRow <= w->hexagons.size - 1) ?
  1430.           pos - w->hexagons.size - posRow :
  1431.           pos - 3 * w->hexagons.size + posRow + 1;
  1432.       }
  1433.       break;
  1434.     case TLBR:
  1435.       if (side == HIGH) {
  1436.         *tileRow = posRow;
  1437.         *tilePos = pos - 1;
  1438.       } else /* side == LOW */ {
  1439.         *tileRow = posRow - 1;
  1440.         *tilePos = (posRow <= w->hexagons.size - 1) ?
  1441.           pos - w->hexagons.size - posRow + 1 :
  1442.           pos - 3 * w->hexagons.size + posRow + 2;
  1443.       }
  1444.       break;
  1445.     case ROW:
  1446.       if (side == HIGH) {
  1447.         *tileRow = posRow + 1;
  1448.         *tilePos = (posRow < w->hexagons.size - 1) ?
  1449.           pos + w->hexagons.size + posRow :
  1450.           pos + 3 * w->hexagons.size - posRow - 3;
  1451.       } else /* side == LOW */ {
  1452.         *tileRow = posRow - 1;
  1453.         *tilePos = (posRow <= w->hexagons.size - 1) ?
  1454.           pos - w->hexagons.size - posRow :
  1455.           pos - 3 * w->hexagons.size + posRow + 1;
  1456.       }
  1457.       break;
  1458.     default:
  1459.       (void) printf("FindMovableTile: spaceType %d.\n", spaceType);
  1460.    }
  1461. }
  1462.  
  1463. static void DrawFrame(w, gc)
  1464.   HexagonsWidget w;
  1465.   GC gc;
  1466. {
  1467.   int sumX, sumY, sumX4, sum3X4, sumY2, offsetX, offsetY;
  1468.  
  1469.   sumX = w->hexagons.size * (2 * w->hexagons.offset.x) -
  1470.     w->hexagons.tileSize.x / 2 - 2 * w->hexagons.delta.x - 1;
  1471.   sumY = w->hexagons.size * (3 * w->hexagons.tileSize.y + 2 *
  1472.     w->hexagons.delta.y) - w->hexagons.tileSize.y - 1;
  1473.   offsetX = w->hexagons.puzzleOffset.x - 1;
  1474.   offsetY = w->hexagons.puzzleOffset.y;
  1475.   sumX4 = sumX / 4 + offsetX;
  1476.   sum3X4 = 3 * sumX / 4 + offsetX + 2;
  1477.   sumY2 = sumY / 2 + offsetY;
  1478.   sumX += offsetX + 1 + w->hexagons.size / 2;
  1479.   sumY += offsetY;
  1480.   offsetX += 1 - w->hexagons.size / 2;
  1481.   XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1482.     sumX4, offsetY, sum3X4, offsetY);
  1483.   XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1484.     sum3X4, offsetY, sumX, sumY2);
  1485.   XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1486.     sumX, sumY2, sum3X4, sumY);
  1487.   XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1488.     sum3X4, sumY, sumX4, sumY);
  1489.   XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1490.     sumX4, sumY, offsetX, sumY2);
  1491.   XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1492.     offsetX, sumY2, sumX4, offsetY);
  1493. }   
  1494.  
  1495. void DrawAllTiles(w, tileGC, borderGC)
  1496.   HexagonsWidget w;
  1497.   GC tileGC, borderGC;
  1498. {
  1499.   int k;
  1500.  
  1501.   for (k = 0; k < w->hexagons.sizeSize; k++)
  1502.     if (w->hexagons.tileOfPosition[k] <= 0)
  1503.       DrawTile(w, w->hexagons.inverseGC, w->hexagons.inverseGC, k, FALSE);
  1504.     else
  1505.       DrawTile(w, tileGC, borderGC, k, FALSE);
  1506. }
  1507.  
  1508. static void DrawTile(w, tileGC, borderGC, pos, offset)
  1509.   HexagonsWidget w;
  1510.   GC tileGC, borderGC;
  1511.   int pos, offset;
  1512. {
  1513.   int dx, dy, k = Row(w, pos), orient = (w->hexagons.corners) ? 1 : 0;
  1514.  
  1515.   dx = w->hexagons.tileSize.x / 4 - 1 + (2 * TrBl(w, pos, k) +
  1516.     w->hexagons.size - k) * w->hexagons.offset.x / 2 +
  1517.     w->hexagons.puzzleOffset.x + offset;
  1518.   dy = k * (3 * w->hexagons.tileSize.y / 2 + w->hexagons.delta.y) +
  1519.     w->hexagons.delta.y - 1 + w->hexagons.puzzleOffset.y + offset;
  1520.   if (orient) {
  1521.     hexagonList[orient][0].x = dx;
  1522.     hexagonList[orient][0].y = dy;
  1523.   } else {
  1524.     hexagonList[orient][0].x = dx - w->hexagons.offset.x / 4;
  1525.     hexagonList[orient][0].y = dy +
  1526.       (w->hexagons.tileSize.y + w->hexagons.delta.y) / 4;
  1527.   }
  1528.   XFillPolygon(XtDisplay(w), XtWindow(w), tileGC, hexagonList[orient], 6,
  1529.     Convex, CoordModePrevious);
  1530.   XDrawLines(XtDisplay(w), XtWindow(w), borderGC, hexagonList[orient], 7,
  1531.     CoordModePrevious);
  1532.   if (tileGC != w->hexagons.inverseGC) {
  1533.     int i = 0, offsetX = 0;
  1534.     int tile = w->hexagons.tileOfPosition[pos];
  1535.     char buf[5];
  1536.  
  1537.     (void) sprintf(buf, "%d", tile);
  1538.     while (tile >= 1) {
  1539.       tile /= w->hexagons.base;
  1540.       offsetX += w->hexagons.digitOffset.x;
  1541.       i++;
  1542.     }
  1543.     XDrawString(XtDisplay(w), XtWindow(w), w->hexagons.inverseGC,
  1544.       dx - offsetX,
  1545.       dy + w->hexagons.tileSize.y + w->hexagons.digitOffset.y, buf, i);
  1546.   }
  1547. }
  1548.  
  1549. #ifdef DEBUG
  1550. static int PositionInRow(w, position, posRow)
  1551.   HexagonsWidget w;
  1552.   int position, posRow;
  1553. {
  1554.   return (posRow <= w->hexagons.size - 1) ?
  1555.     (position - w->hexagons.size * posRow - posRow * (posRow - 1) / 2) :
  1556.     (position - w->hexagons.size * (posRow - w->hexagons.size) -
  1557.       4 * w->hexagons.size * (w->hexagons.size - 1) / 2 + (2 *
  1558.       w->hexagons.size - posRow - 2) * (2 * w->hexagons.size - posRow - 1) /
  1559.       2 - 1);
  1560. }
  1561. #endif
  1562.  
  1563. static int PositionFromRow(w, rowPosition, posRow)
  1564.   HexagonsWidget w;
  1565.   int rowPosition, posRow;
  1566. {
  1567.   return (posRow <= w->hexagons.size - 1) ?
  1568.     (w->hexagons.size * posRow + posRow * (posRow - 1) / 2 + rowPosition) :
  1569.     (w->hexagons.size * (posRow - w->hexagons.size) + 4 *
  1570.       w->hexagons.size * (w->hexagons.size - 1) / 2 - (2 * w->hexagons.size -
  1571.       posRow - 2) * (2 * w->hexagons.size - posRow - 1) / 2 + 1 + rowPosition);
  1572. }
  1573.  
  1574. int Row(w, pos)
  1575.   HexagonsWidget w;
  1576.   int pos;
  1577. {
  1578.   return (pos <= w->hexagons.sizeCenter) ?
  1579.     (1 + Sqrt(1 + 8 * (pos + w->hexagons.size *
  1580.     (w->hexagons.size - 1) / 2))) / 2 - w->hexagons.size :
  1581.     3 * w->hexagons.size - 2 - (1 + Sqrt(1 + 8 * (w->hexagons.sizeSize - 1 +
  1582.     w->hexagons.size * (w->hexagons.size - 1) / 2 - pos))) / 2;
  1583. }
  1584.  
  1585. /* Passing row so there is no sqrt calculation again */
  1586. int TrBl(w, pos, posRow)
  1587.   HexagonsWidget w;
  1588.   int pos, posRow;
  1589. {
  1590.   return (pos <= w->hexagons.sizeCenter) ?
  1591.     (pos + w->hexagons.size * (w->hexagons.size - 1) / 2) -
  1592.     (posRow + w->hexagons.size) * (posRow + w->hexagons.size - 1) / 2 :
  1593.     2 * w->hexagons.size - 2 - (w->hexagons.sizeSize - 1 +
  1594.     w->hexagons.size * (w->hexagons.size - 1) / 2 - pos -
  1595.     (3 * w->hexagons.size - posRow - 2) * (3 * w->hexagons.size - posRow - 3) /
  1596.     2);
  1597. }
  1598.  
  1599. int TlBr(w, pos, posRow)
  1600.   HexagonsWidget w;
  1601.   int pos, posRow;
  1602. {
  1603.   return (pos <= w->hexagons.sizeCenter) ?
  1604.     -1 - ((pos + w->hexagons.size * (w->hexagons.size - 1) / 2) -
  1605.     (posRow + w->hexagons.size + 1) * (posRow + w->hexagons.size) / 2):
  1606.     2 * w->hexagons.size - 1 + (w->hexagons.sizeSize - 1 +
  1607.     w->hexagons.size * (w->hexagons.size - 1) / 2 - pos -
  1608.     (3 * w->hexagons.size - posRow - 1) * (3 * w->hexagons.size - posRow - 2) /
  1609.     2);
  1610. }
  1611.  
  1612. /* This is fast for small i, a -1 is returned for negative i. */
  1613. static int Sqrt(i)
  1614.   int i;
  1615. {
  1616.   int j = 0;
  1617.  
  1618.   while (j * j <= i)
  1619.     j++;
  1620.   return (j - 1);
  1621. }
  1622.  
  1623. Boolean CheckSolved(w)
  1624.   HexagonsWidget w;
  1625. {
  1626.   int i;
  1627.  
  1628.   for (i = 1; i < w->hexagons.sizeSize - ((w->hexagons.corners) ? 1 : 0); i++)
  1629.     if (w->hexagons.tileOfPosition[i - 1] != i)
  1630.       return FALSE;
  1631.   return TRUE;
  1632. }
  1633.  
  1634. static void swap(a, b)
  1635.   int *a, *b;
  1636. {
  1637.   int c;
  1638.  
  1639.   c = *b;
  1640.   *b = *a;
  1641.   *a = c;
  1642. }
  1643.